package com.thb.pay.channel;

import com.thb.pay.api.order.vo.req.PayOrderReq;
import com.thb.pay.api.payment.PayChannelServiceApi;
import com.thb.pay.api.payment.vo.resp.PayChannelVo;
import com.thb.pay.comm.dto.ExtraInfoDTO;
import com.thb.pay.comm.utils.PaymentResult;
import com.thb.pay.core.context.ApplicationContextHelper;
import com.thb.pay.core.exception.RRException;
import com.thb.pay.core.utils.IdWorker;
import com.thb.pay.exception.PaymentGatewayEnum;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @类名称 AbsPaymentService
 * @类描述 <pre>支付抽象类实现</pre>
 * @作者 lucky
 * @创建时间 2019/10/24
 * @版本 v1.01
 */
public abstract class AbsPaymentService implements IPaymentService {

    protected static final Logger logger = LoggerFactory.getLogger(AbsPaymentService.class);

    @Autowired
    private PayChannelServiceApi payChannelServiceApi;

    public abstract String channel();

    protected String getPaymentMethod(String channelCode) {
        StringBuilder sb = new StringBuilder();
        for (String str : channelCode.split("_")) {
            if (sb.length() <= 0) {
                sb.append(str);
                continue;
            }
            sb.append(str.substring(0, 1).toUpperCase()).append(str.substring(1));
        }
        return sb.toString();
    }

    @Override
    public PaymentResult payOrder(PayOrderReq payOrder) {
        PayChannelVo payChannelVo = payChannelServiceApi.getById(payOrder.getChannelId());
        if (payChannelVo == null) {
            //通道未配置对应的通道支付方式
            throw RRException.build(PaymentGatewayEnum.SYSTEM_ERROR, String.format("支付渠道类型[channelId=%s]实例化异常", payOrder.getChannelId()));
        }
        Object targetPaymentService = ApplicationContextHelper.getBean(channel() + "PaymentService");
        if (targetPaymentService == null) {
            //通道未配置对应的通道支付方式
            throw RRException.build(PaymentGatewayEnum.SYSTEM_ERROR, String.format("支付渠道类型[channelId=%s]实例化异常", payOrder.getChannelId()));
        }
        try {
            Method method = targetPaymentService.getClass().getMethod(this.getPaymentMethod(payChannelVo.getCode()), PayOrderReq.class);
            try {
                return (PaymentResult) method.invoke(targetPaymentService, payOrder);
            } catch (IllegalAccessException e) {
                logger.error("pay.channel:{}.method:{}.IllegalAccessException.error", payOrder.getChannelTypeId(), payChannelVo.getCode());
                throw RRException.build(PaymentGatewayEnum.SYSTEM_ERROR, String.format("支付渠道类型[channelId=%s]实例化异常", payOrder.getChannelId()));
            } catch (InvocationTargetException e) {
                logger.error("pay.channel:{}.method:{}.InvocationTargetException.error", payOrder.getChannelTypeId(), payChannelVo.getCode());
                throw RRException.build(PaymentGatewayEnum.SYSTEM_ERROR, String.format("支付渠道类型[channelId=%s]实例化异常", payOrder.getChannelId()));
            }
        } catch (NoSuchMethodException e) {
            logger.warn("not.channel.payMethod.by.channelMethodCode.{}", payChannelVo.getCode());
            throw RRException.build(PaymentGatewayEnum.SYSTEM_ERROR, String.format("支付渠道类型[channelId=%s]实例化异常", payOrder.getChannelId()));
        }
    }

    @Override
    public Object cancelOrder(PayOrderReq payOrder) {
        return null;
    }

    @Override
    public Object queryOrder(PayOrderReq payOrder) {
        return null;
    }

    @Override
    public String generateOrderNumber(PayOrderReq payOrder) {
        //默认按系统的订单号规则[通道有实现则按照通道的规则实现]
        return IdWorker.getIdStr();
    }

    @Override
    public Long currencyExchange(PayOrderReq payOrder) {
        return null;
    }

    @Override
    public String getThirdPayConfig(PayOrderReq payOrder) {
        Long channelId = payOrder.getChannelId();
        PayChannelVo payChannelVo = payChannelServiceApi.getById(channelId);
        String params = payChannelVo.getParam();
        if (StringUtils.isNotBlank(params)) {
            return params;
        }
        return null;
    }

    @Override
    public ExtraInfoDTO checkExtra(String extra) {
        return null;
    }
}
